package com.zyh.cxf;

import com.zyh.dao.KeyMapper;
import com.zyh.dao.TrandMapper;
import com.zyh.pojo.Zjywpt_yg_trand_infos;
import com.zyh.service.BaseService;
import com.zyh.util.*;
import com.zyh.util.ESBQRCB01.*;
import com.zyh.util.ESBQRCB02.ESBErrorQRCBBody02;
import com.zyh.util.ESBQRCB02.ESBQRCBHead02;
import com.zyh.util.ESBQRCB02.EsbErrorResponseQRCB02;
import com.zyh.util.safeutil.DESedeUtil;
import com.zyh.util.safeutil.SM2Utils;
import com.zyh.util.safeutil.Util;
import org.apache.cxf.phase.PhaseInterceptorChain;
import org.apache.cxf.transport.http.AbstractHTTPDestination;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author shihan
 * @date 2020-12-04-14:00
 */
@Component
public class GetAccountBalanceImpl implements GetAccountBalance {

    @Autowired
    private TrandMapper trandMapper;
    public static GetAccountBalanceImpl getAccountBalance;


    @Autowired
    private KeyMapper keyMapper;

    @PostConstruct
    public void init() {

        getAccountBalance = this;
        getAccountBalance.trandMapper = this.trandMapper;
    }

    public static void addGetAcc(Zjywpt_yg_trand_infos zjywpt_yg_trand_infos) {

        getAccountBalance.trandMapper.addTrand(zjywpt_yg_trand_infos);
    }

    @Override
    public String  getABalance(String xmlData) {
        /*
        try {
            Thread.sleep(30000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

         */


        Map<String, Object> keyMap = keyMapper.querykey();
        //查询加密的公钥
        String inencryptKey=(String)keyMap.get("PublicKey");
        String privateKey=(String)keyMap.get("PrivateKey");
        //第一步密钥解密
        System.err.println("密钥sm2私钥解密：");
        String plainText = null;
        try {
            plainText = new String(SM2Utils.decrypt(Util.hexToByte(privateKey), Util.hexToByte(inencryptKey)));
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("密钥明文：" + plainText);
        // 第二步通过拿到的解密密钥进行报文解密
        String inresource = null;
        try {
            inresource = DESedeUtil.decrypt(xmlData, plainText);
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println("医保端明文："+ inresource);




//        //获得医保端的请求参数
//        HttpServletRequest request = (HttpServletRequest) PhaseInterceptorChain.getCurrentMessage().get(AbstractHTTPDestination.HTTP_REQUEST);
//
//        String reqName = request.getParameter("name");

        //落库记录表对象
        Zjywpt_yg_trand_infos zjywpt_yg_trand_infos = new Zjywpt_yg_trand_infos();
        //交易日期
        String RECDATE = RandomNumber.productTxnDt();
        //交易时间
        String RETDATE = RandomNumber.productTxnTm();
        zjywpt_yg_trand_infos.setRECDATE(RECDATE);
        zjywpt_yg_trand_infos.setRETDATE(RETDATE);


        // 全局流水号ESBID
        String ESBID = RandomNumber.productBsnSrNo();


        //用于接收 医保端“查询余额请求”的账号字段-PayerAcNO

        Map<String, String> mapQRC01 = doRequestObj(inresource);
        String PayerAcNO = mapQRC01.get("PayerAcNo");
        String serialNo = mapQRC01.get("serialNo");

        if( PayerAcNO.length() == 0){

            //返回错误响应
            return  errorXml(ESBID,"000","请求账户不合法,不应为空",plainText);

        }

        try {
            Float a = Float.valueOf(PayerAcNO);
        }catch (NumberFormatException e){

            //返回错误响应
            return  errorXml(ESBID,"000","账户应为数字",plainText);

        }

        if( PayerAcNO.length() != 17){

            //返回错误响应
            return  errorXml(ESBID,"000","请求账户不合法,应为17位数字",plainText);

        }

        String   mainAccNo = this.trandMapper.queryAccNoById(PayerAcNO);


        if(mainAccNo == null){

            //返回错误响应
            return  errorXml(ESBID,"000","该账户不在本行系统中，请再次核对",plainText);
        }


        //解析请求，获得请求具体行为【拼接为ESB的请求】
        String xmlESBRequest = getXmlInfo(ESBID, PayerAcNO);

        //调用Socket发送 【返回ESB响应】
        String xmlESBResponse = SocketUtils.sendData(xmlESBRequest);

        System.out.println("esb-response" + xmlESBResponse);

        // 获得ESB返回参数，解析成对象
        //通过返回码 假定 RetCd=000000 为正常报文
        EsbResponseQRCB01 esbResponseQRCB01 = null;
        ESBQRCBHead esbqrcbHead = null;
        String responseToYBxml = null;
        String zjstatus = "";

        String ESBMSG = "";
        String returnCode = "";
        String IBSJnlNo = "";
        if (xmlESBResponse.length() > 0) {
            try {
                esbResponseQRCB01 = Dom23.doESBResponseObj01(xmlESBResponse, serialNo);

                responseToYBxml = XstreamKit.vo2Xml(esbResponseQRCB01);


                esbqrcbHead = esbResponseQRCB01.getEsbqrcbHead();
                returnCode = esbqrcbHead.getIBSReturnCode();

                //90成功 91失败
                ESBMSG = esbqrcbHead.getIBSReturnMsg();
                IBSJnlNo = esbqrcbHead.getIBSJnlNo();
                zjywpt_yg_trand_infos.setESBMSG(ESBMSG);
                zjywpt_yg_trand_infos.setESBID(ESBID);
                zjywpt_yg_trand_infos.setESBSTATUS(esbqrcbHead.getIBSReturnCode());

                zjywpt_yg_trand_infos.setESBServiceCode("30013000101");
                zjywpt_yg_trand_infos.setESBOUT(xmlESBResponse);
                zjywpt_yg_trand_infos.setESBIN(xmlESBRequest);

                zjywpt_yg_trand_infos.setYBIN(inresource);
                zjywpt_yg_trand_infos.setYBOUT(responseToYBxml);
                //加密发送给医保端
                try {
                    responseToYBxml = DESedeUtil.encrypt(responseToYBxml, plainText);
                } catch (Exception e) {
                    e.printStackTrace();
                }

                zjywpt_yg_trand_infos.setCreator("");
                zjywpt_yg_trand_infos.setCreationtime("");
                zjywpt_yg_trand_infos.setModifier("");
                zjywpt_yg_trand_infos.setModifiedtime("");
                zjywpt_yg_trand_infos.setINTERFACENO("QRCB001");

                //ESB 成功后返回代码为 000000
                if ("000000".equals(returnCode)) {

                    zjywpt_yg_trand_infos.setSTATUS("90");

                    zjywpt_yg_trand_infos.setESBMSG("账户余额查询成功");
                    addGetAcc(zjywpt_yg_trand_infos);

                    return responseToYBxml;
                } else {


                    EsbErrorResponseQRCB01 esbErrorResponseQRCB01 = new EsbErrorResponseQRCB01();
                    ESBQRCBHead esbqrcbHead1 = new ESBQRCBHead();
                    esbqrcbHead1.setIBSJnlNo(IBSJnlNo);
                    esbqrcbHead1.setIBSReturnCode(returnCode);
                    esbqrcbHead1.setIBSReturnMsg(ESBMSG);
                    esbErrorResponseQRCB01.setEsbqrcbHead(esbqrcbHead1);

                    ESBErrorQRCBBody01 esbErrorQRCBBody01 = new ESBErrorQRCBBody01();
                    esbErrorQRCBBody01.setOrderState("91");
                    esbErrorQRCBBody01.setOrderFlowDescript(ESBMSG);
                    esbErrorResponseQRCB01.setEsbErrorQRCBBody01(esbErrorQRCBBody01);

                    zjywpt_yg_trand_infos.setSTATUS("91");

                    zjywpt_yg_trand_infos.setESBMSG("账户余额查询失败");
                    addGetAcc(zjywpt_yg_trand_infos);

                    responseToYBxml = XstreamKit.vo2Xml(esbErrorResponseQRCB01);

                    //加密发送给医保端
                    try {
                        responseToYBxml = DESedeUtil.encrypt(responseToYBxml, plainText);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                    return responseToYBxml;

                }

            } catch (DocumentException e) {
                e.printStackTrace();
            }
        } else {

            return   errorXml(ESBID,"000","ESB系统繁忙，请稍后再试",plainText);
        }


        return responseToYBxml;
    }


    //生成xml格式数据
    private String getXmlInfo(String uuid, String PayerAcNO) {


        Document doc = DocumentHelper.createDocument();
        Element service = doc.addElement("service");
        Element SysHead = service.addElement("SysHead");
        Element AppHead = service.addElement("AppHead");
        Element LocalHead = service.addElement("LocalHead");
        Element Body = service.addElement("Body");

        Element SvcCd = SysHead.addElement("SvcCd");
        Element ScnCd = SysHead.addElement("ScnCd");
        Element CnsmrSysNo = SysHead.addElement("CnsmrSysNo");
        Element BsnSrlNo = SysHead.addElement("BsnSrlNo");
        Element TxnDtEle = SysHead.addElement("TxnDt");
        Element TxnTmEle = SysHead.addElement("TxnTm");

        SvcCd.setText("300130001");
        ScnCd.setText("01");
        CnsmrSysNo.setText(ConfigInfo.getConfigInfoByName("esb.CnsmrSysNo"));
        BsnSrlNo.setText(uuid);
        TxnDtEle.setText(RandomNumber.productTxnDt());
        TxnTmEle.setText(RandomNumber.productTxnTm());


        Element CnlCd = AppHead.addElement("CnlCd");
        Element InstNo = AppHead.addElement("InstNo");
        Element OtltsNo = AppHead.addElement("OtltsNo");
        Element UsrNo = AppHead.addElement("UsrNo");


        CnlCd.setText(ConfigInfo.getConfigInfoByName("esb.cnlCd"));
        InstNo.setText("003");
        OtltsNo.setText("10001");
        UsrNo.setText("8170004");


        Element TlrTp = LocalHead.addElement("TlrTp");
        Element AuthTlrNo = LocalHead.addElement("AuthTlrNo");
        Element OldAcctFlg = LocalHead.addElement("OldAcctFlg");


        TlrTp.setText("0");
        AuthTlrNo.setText("0000000");
        OldAcctFlg.setText("1");


        Element ProvCd = Body.addElement("ProvCd");
        Element OldAcctOfstLo = Body.addElement("OldAcctOfstLo");
        Element CstAcctNo = Body.addElement("CstAcctNo");
        Element QryFcnOptn = Body.addElement("QryFcnOptn");
        Element OptnFlg1 = Body.addElement("OptnFlg1");
        Element OptnFlg2 = Body.addElement("OptnFlg2");


        ProvCd.setText("63");
        OldAcctOfstLo.setText("29");
        CstAcctNo.setText(PayerAcNO);
        QryFcnOptn.setText("T");
        OptnFlg1.setText("0");
        OptnFlg2.setText("0");


        String docData = doc.asXML();
        byte[] bytes = docData.getBytes();
        System.out.println(bytes.length);
        String format = String.format("%08d", bytes.length);
        System.out.println("dfsdfs=" + format);
        System.out.println("发送的xml:" + doc.asXML());
        return format + doc.asXML();
    }


    //解析医保端请求方的XML数据
    private Map<String, String> doRequestObj(String xmlData) {
        Map<String, String> mapQRC01 = new HashMap<>();
        Document doc = null;
        try {
            doc = DocumentHelper.parseText(xmlData);
            Element rootElt = doc.getRootElement();

            // 只返回 Head 内容
            Iterator itersHead = rootElt.elementIterator("Head");

            while (itersHead.hasNext()) {

                Element reEless = (Element) itersHead.next();
                String serialNo = reEless.elementTextTrim("serialNo");
                String reqTime = reEless.elementTextTrim("reqTime");

                mapQRC01.put("serialNo", serialNo);
                mapQRC01.put("reqTime", reqTime);

            }

            // 只返回 Body 内容
            Iterator itersBody = rootElt.elementIterator("Body");
            while (itersBody.hasNext()) {

                Element reEless = (Element) itersBody.next();
                //账户余额查询用账户号【解析传入】
                String PayerAcNO = reEless.elementTextTrim("PayerAcNo");
                String PayerCurrency = reEless.elementTextTrim("PayerCurrency");

                mapQRC01.put("PayerAcNo", PayerAcNO);
                mapQRC01.put("PayerCurrency", PayerCurrency);

            }


        } catch (DocumentException e) {
            System.out.println(e.getMessage());
        }

        return mapQRC01;
    }


    public ESBQRCB01AccTop getAcctOpnOtltsNo(String uuid, String PayerAcNO) {
        //解析请求，获得请求具体行为【拼接为ESB的请求】

        //PayerAcNO = "82010000000303251";
        String xmlESBRequest = getXmlInfo(uuid, PayerAcNO);

        //调用Socket发送 【返回ESB响应】
        String xmlESBResponse = SocketUtils.sendData(xmlESBRequest);

        System.out.println("esb-response" + xmlESBResponse);
        ESBQRCB01AccTop esbqrcb01AccTop = new ESBQRCB01AccTop();
        try {
            esbqrcb01AccTop = Dom23.doESBResponseAccTopObj(xmlESBResponse);


        } catch (DocumentException e) {
            e.printStackTrace();
        }
        return esbqrcb01AccTop;
    }

    @Test
    public void Test() {

        String PayerAcNO = "82010000000303239";
        String xmlESBRequest = getXmlInfo(RandomNumber.productBsnSrNo(), PayerAcNO);

        //调用Socket发送 【返回ESB响应】
        String xmlESBResponse = SocketUtils.sendData(xmlESBRequest);

        System.out.println("esb-response" + xmlESBResponse);
        ESBQRCB01AccTop esbqrcb01AccTop = new ESBQRCB01AccTop();
        try {
            esbqrcb01AccTop = Dom23.doESBResponseAccTopObj(xmlESBResponse);


        } catch (DocumentException e) {
            e.printStackTrace();
        }

    }


    public String errorXml(String IBSJnlNo,String returnCode,String ESBMSG,String key){

        EsbErrorResponseQRCB02 esbErrorResponseQRCB02 = new EsbErrorResponseQRCB02();
        ESBQRCBHead02 esbqrcbHead2 = new ESBQRCBHead02();
        esbqrcbHead2.setIBSJnlNo(IBSJnlNo);
        esbqrcbHead2.setIBSReturnCode(returnCode);
        esbqrcbHead2.setIBSReturnMsg(ESBMSG);
        esbErrorResponseQRCB02.setEsbqrcbHead02(esbqrcbHead2);

        ESBErrorQRCBBody02 esbErrorQRCBBody02 = new ESBErrorQRCBBody02();
        esbErrorQRCBBody02.setOrderState("91");
        esbErrorQRCBBody02.setOrderFlowDescript(ESBMSG);
        esbErrorResponseQRCB02.setEsbErrorQRCBBody02(esbErrorQRCBBody02);

        String errorXml  = XstreamKit.vo2Xml(esbErrorResponseQRCB02);
        //加密发送给医保端
        try {
            errorXml = DESedeUtil.encrypt(errorXml, key);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return errorXml;
    }
}
